#include <netdb.h>
#include "CCReactor.h"
#include "UdpListener.h"
#include "GameBase.h"

extern CMemPool*	_memPool;
UdpListener::UdpListener(CGameBase* pServer) :
	m_pServer(pServer),
	_r(_memPool),
	_w(_memPool)
{

}

UdpListener::~UdpListener()
{
}
 
int UdpListener::Listen(const char* bindIp, uint16_t port)
{
	if(!bindIp)
	{
		return -1;
	}
	strncpy (_bindAddr, bindIp, sizeof(_bindAddr) - 1);
	_bindPort = port;

	if((netfd = CNet::udp_bind(_bindAddr, _bindPort)) == -1)
	{
		log_error ("upd bind addr[%s], port[%d] failed.", _bindAddr, _bindPort);
		return -1;
	}

	CPollerObject::EnableInput ();
	CCReactor::Instance()->AttachPoller(this);
	log_boot("server fd[%d] bind addr[%s], port[%d] listening ...\n", netfd, _bindAddr, _bindPort);

	return 0;
}

int UdpListener::InputNotify(void)
{
	int	ret = 0;
	int	packet_len = 0;
	int	curr_recv_len = 0;
	char curr_recv_buf[MAX_UDP_RECV_LEN] = { 0 };
	struct sockaddr_in peer_addr = { 0 };
	socklen_t peer_addr_len = sizeof(peer_addr);

	curr_recv_len = recvfrom(netfd, curr_recv_buf, sizeof(curr_recv_buf), 0,
		(struct sockaddr *) &peer_addr, &peer_addr_len);

	log_debug("*STEP: receiving data, length[%d]\n", curr_recv_len);

	if (-1 == curr_recv_len)
	{//接收数据有误
		if (errno != EAGAIN && errno != EINTR && errno != EINPROGRESS)
		{
			log_error("upd recv failed from fd[%d], err_msg[%s]", netfd, strerror(errno));
			return POLLER_FAIL;
		}
		return POLLER_SUCC;  // recv again
	}
	else
	{
		m_pServer->ProccessUpdPacket(curr_recv_buf, curr_recv_len, peer_addr);
	}

	return POLLER_SUCC;
}



int UdpListener::generate_addr(char *domain, int port, struct sockaddr_in *addr)
{
	char ip[64] = {0};
	bzero(addr, sizeof(struct sockaddr_in));
	addr->sin_family = AF_INET;
	addr->sin_port = htons(port);

	if (strcmp(domain, "*") == 0 || strcmp(domain, "0.0.0.0") == 0) {
		addr->sin_addr.s_addr = htonl(INADDR_ANY);
	} else {
		struct hostent *host = gethostbyname(domain);
		if (!host) {
			printf("gethostbyname fail");
			return -1;
		}
		strncpy(ip, inet_ntoa(*(struct in_addr *)host->h_addr), sizeof(ip)-1);
		//strncpy(ip, inet_ntoa(*(struct in_addr *)host->h_addr), sizeof(ip) - 1);

		if (inet_pton(AF_INET, ip, &(addr->sin_addr)) <= 0) {
			printf("inet_pton fail");
			return -1;
		}
	}
	return 0;
}


int UdpListener::Send(const char * buff, int len, char* ip, int port)
{  // do not use this method
	if(len>0)
	{
		const char* sendbuff = buff;
		int sendlen = len;

		if(this->_w.data_len()==0)
		{
			struct sockaddr_in addr={0};

			generate_addr(ip, port, &addr);
			int ret = ::sendto(netfd, buff, len, 0, (struct sockaddr*)&addr, sizeof(addr));
			if(-1 == ret)
			{
				if(errno == EINTR || errno == EAGAIN || errno == EINPROGRESS)
				{
					log_warning("sending,INTR|EAGAIN|EINPROGRESS,errno:[%d]", errno);
					return len;
				}

				log_debug("send err. ret=%d",ret);
				return -1;
			}
			else if(ret<len)
			{
				log_debug("send err. not complete send len=[%d],total len=%d",ret,len);
				return -1;
			}
			else if(ret==len)
			{
				log_debug("send complete, send len=[%d]",len);
				return ret;
			}
		}
		else
		{
			this->_w.append(sendbuff, sendlen);
			//return  handle_output();
			return 0;
		}
	}

	return -1;
}


